package com.wind.utils.cipher;

import java.io.UnsupportedEncodingException;
import java.net.URLDecoder;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;

/**
 * 加密工具类
 * MD5（Message-Digest Algorithm 5）和SHA-1（Secure Hash Algorithm 1）
 *
 * MD5
 * 用途：MD5由Ron Rivest在1991年设计，最初被用来作为一种安全的密码散列算法。
 * 输出：MD5算法产生一个128位（16字节）的哈希值，通常用32位的十六进制字符串表示。
 * 安全性：MD5的安全性已经受到质疑，存在多种方式可以找到两个不同的输入值但产生相同MD5哈希值的情况（即哈希碰撞）。因此，MD5不再推荐用于需要高安全性的场合，如数字签名、证书等。
 *
 * SHA-1
 * 用途：SHA-1是SHA家族中的第一个算法，由美国国家安全局（NSA）设计，并由NIST发布为联邦信息处理标准。
 * 输出：SHA-1算法产生一个160位（20字节）的哈希值，通常用40位的十六进制字符串表示。
 * 安全性：SHA-1也已经被证明存在安全隐患，尽管它比MD5更安全，但已经不推荐用于需要高安全性的场合。
 * 2017年，谷歌研究人员展示了第一个SHA-1哈希碰撞实例，这进一步证实了SHA-1的不安全性。
 *
 * 不可逆性：MD5和SHA-1都是单向函数，意味着从哈希值几乎不可能逆向推导出原始输入数据
 */
public class CipherUtil {

    /**
     * md5
     * @param str
     * @return
     */
    public static byte[] md5(String str){
        return encrypt(str, "MD5");
    }

    /**
     * md5
     * @param str
     * @return
     */
    public static String md5Str(String str){
        return byte2Hex(md5(str));
    }

    /**
     * SHA1
     * @param str
     * @return
     */
    public static byte[] sha1(String str){
        return encrypt(str, "SHA1");
    }

    /**
     * SHA1
     * @param str
     * @return
     */
    public static String sha1Str(String str){
        return byte2Hex(sha1(str));
    }

    /**
     * md5加密
     * @param str
     * @param key  MD5  SHA1
     * @return
     */
    public static byte[] encrypt(String str, String key){
        try {
            MessageDigest md = MessageDigest.getInstance(key);
            byte[] input = str.getBytes(StandardCharsets.UTF_8);
            return md.digest(input);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * url编码
     * @param str
     * @return
     */
    public static String encodeUrl(String str){
        String s = null;
        try {
            s = URLEncoder.encode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return s;
    }

    /**
     * url解码
     * @param str
     * @return
     */
    public static String decodeUrl(String str){
        String s = null;
        try {
            s = URLDecoder.decode(str, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return s;
    }

    /**
     * Base64编码
     * Base64编码将每3个字节的二进制数据转换为4个字符。如果原始数据的字节数不是3的倍数，那么会添加一些填充字符（通常是=）来补足
     * @param str
     * @return
     */
    public static String encodeBase64(String str){
        return Base64.getEncoder().encodeToString(str.getBytes());
    }

    /**
     * Base64解码
     * Base64编码将每3个字节的二进制数据转换为4个字符。如果原始数据的字节数不是3的倍数，那么会添加一些填充字符（通常是=）来补足
     * @param str
     * @return
     */
    public static String decodeBase64(String str){
        return new String(Base64.getDecoder().decode(str));
    }

    /**
     * 十进制byte数组转成16进制字符串
     * @param bytes
     * @return
     */
    public static String byte2Hex(byte[] bytes) {
        StringBuilder hexString = new StringBuilder();
        for (byte b : bytes) {
            String hex = Integer.toHexString(0xff & b);
            if (hex.length() == 1) {
                hexString.append('0');
            }
            hexString.append(hex);
        }
        return hexString.toString();
    }

    /**
     * 16进制字符串转换成十进制byte数组
     * @param hexStr
     * @return
     */
    public static byte[] hex2Byte(String hexStr){
        int len = hexStr.length();
        byte[] bytes = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            bytes[i / 2] = (byte) ((Character.digit(hexStr.charAt(i), 16) << 4)
                    + Character.digit(hexStr.charAt(i+1), 16));
        }
        return bytes;
    }

    /**
     * 十进制数组转16进制字符串
     * 15(dec) -> 1111(binary) -> 0xf(hex)
     * @param bytes
     * @return
     */
    public static String byte2Hex2(byte[] bytes) {
        // 首先初始化一个字符数组，用来存放每个16进制字符
        String hexStr = "0123456789abcdef";
        char[] arr = new char[bytes.length * 2];
        // 遍历字节数组，通过位运算（位运算效率高），转换成字符放到字符数组中去
        int index = 0;
        for (byte b : bytes) {
            arr[index++] = hexStr.charAt(b >>> 4 & 0xf);
            arr[index++] = hexStr.charAt(b & 0xf);
        }
        // 字符数组组合成字符串返回
        return new String(arr);
    }

    /**
     * 十六进制转十进制
     * @param hexStr
     * @return
     */
    public static String hex2Dec(String hexStr){
        return String.valueOf(Integer.parseInt(hexStr,16));
    }

}
